Overview
single_stock_analyzer.py is a comprehensive stock analysis utility that extracts and calculates detailed fundamental metrics for any stock from the fundamental_data.json file. It provides deep quarterly and annual financial analysis including P&L statements, ratios, growth metrics, and shareholding patterns.
Purpose
This utility serves to:
Deep-Dive Analysis : Examine individual stock fundamentals in detail
Quick Lookups : Get instant fundamental snapshot for any symbol
Trend Analysis : Calculate QoQ and YoY growth metrics
Valuation Metrics : Compute PEG, Forward P/E, and other valuation ratios
Shareholding Insights : Track institutional ownership changes
How It’s Used
This is a command-line utility that analyzes data from the main pipeline output:
# Analyze a specific stock
python3 single_stock_analyzer.py RELIANCE
# Analyze another stock
python3 single_stock_analyzer.py TCS
Prerequisite:
fundamental_data.json must exist in the same directory (generated by fetch_fundamental_data.py)
What It Analyzes
The analyzer extracts and calculates comprehensive metrics across multiple categories:
1. Profit & Loss (Net Profit)
Latest quarter net profit
Previous 3 quarters
Year-ago quarter (for YoY comparison)
QoQ % change
YoY % change
2. Earnings Per Share (EPS)
Latest quarter EPS
Previous 3 quarters
Year-ago quarter EPS
Last year annual EPS
2 years back annual EPS
QoQ % change
YoY % change
3. Sales (Revenue)
Latest quarter sales
Previous 3 quarters
Year-ago quarter sales
Current year annual sales
5 years ago sales
QoQ % change
YoY % change
5-Year CAGR (Compound Annual Growth Rate)
4. Operating Profit Margin (OPM)
Latest quarter OPM
Previous 3 quarters
Year-ago quarter OPM
TTM (Trailing Twelve Months) OPM
QoQ % change
YoY % change
5. Valuation Ratios
ROE (Return on Equity)
ROCE (Return on Capital Employed)
P/E Ratio (Price to Earnings)
D/E Ratio (Debt to Equity)
PEG Ratio (P/E to Growth)
Forward P/E (estimated)
6. Shareholding Patterns
FII % (Foreign Institutional Investors)
DII % (Domestic Institutional Investors)
QoQ Change in FII/DII holdings
API Reference
Helper Functions
get_float()
Safely converts a value to float, returning 0.0 on failure.
The value to convert to float (can be string, int, float, or None).
Returns: float
eps = get_float( "12.50" ) # Returns 12.50
eps = get_float( None ) # Returns 0.0
eps = get_float( "N/A" ) # Returns 0.0
calculate_change()
Calculates percentage change between two values.
Returns: float - Percentage change
Formula:
change = ((current - previous) / abs (previous)) * 100
Example:
qoq_growth = calculate_change( 100 , 80 ) # Returns 25.0 (25% growth)
yoy_decline = calculate_change( 80 , 100 ) # Returns -20.0 (20% decline)
get_value_from_pipe_string()
Extracts a specific value from pipe-delimited string.
Pipe-delimited string (e.g., “10.5|9.2|8.7|7.5”)
Zero-based index of the value to extract
Returns: float
Example:
# Quarterly data: "12.5|11.0|10.5|9.8"
latest = get_value_from_pipe_string( "12.5|11.0|10.5|9.8" , 0 ) # Returns 12.5
prev = get_value_from_pipe_string( "12.5|11.0|10.5|9.8" , 1 ) # Returns 11.0
Main Function
analyze_stock()
Performs comprehensive fundamental analysis for a given stock symbol.
Stock symbol to analyze (e.g., “RELIANCE”, “TCS”, “INFY”)
Returns: None (prints analysis to console)
Data Sources:
The function extracts data from multiple sections of fundamental_data.json:
stock_data = {
"Symbol" : "RELIANCE" ,
"incomeStat_cq" : {}, # Current Quarter income statement
"incomeStat_cy" : {}, # Current Year annual income statement
"TTM_cy" : {}, # Trailing Twelve Months
"CV" : {}, # Current Valuation
"roce_roe" : {}, # Return ratios
"sHp" : {}, # Shareholding Pattern
"bs_c" : {} # Balance Sheet Consolidated
}
The analyzer prints a detailed report to the console:
--- Analysis for RELIANCE ---
Net Profit Latest Quarter: 15000.0
Net Profit Previous Quarter: 14500.0
Net Profit 2 Quarters Back: 14000.0
Net Profit 3 Quarters Back: 13500.0
Net Profit Last Year Quarter: 12000.0
QoQ % Net Profit Latest: 3.45%
YoY % Net Profit Latest: 25.00%
EPS Latest Quarter: 22.50
EPS Previous Quarter: 21.75
EPS 2 Quarters Back: 21.00
EPS 3 Quarters Back: 20.25
EPS Last Year Quarter: 18.00
QoQ % EPS Latest: 3.45%
YoY % EPS Latest: 25.00%
EPS Last Year: 85.00
EPS 2 Years Back: 75.00
Sales Latest Quarter: 200000.0
Sales Previous Quarter: 195000.0
Sales 2 Quarters Back: 190000.0
Sales 3 Quarters Back: 185000.0
Sales Last Year Quarter: 175000.0
QoQ % Sales Latest: 2.56%
YoY % Sales Latest: 14.29%
Sales Growth 5 Years(%): 12.50%
OPM Latest Quarter: 15.5
OPM Previous Quarter: 15.2
OPM 2 Quarters Back: 14.8
OPM 3 Quarters Back: 14.5
OPM Last Year Quarter: 14.0
QoQ % OPM Latest: 1.97%
YoY % OPM Latest: 10.71%
Latest Quarter: Mar 2024
ROE(%): 12.5
ROCE(%): 14.2
D/E: 0.65
OPM TTM(%): 15.1
P/E: 28.5
FII % change QoQ: 1.25%
DII % change QoQ: -0.50%
PEG: 1.14
Forward P/E: 26.80
Historical P/E 5: 0 (Data Unavailable)
Usage
Command Line
# Analyze a stock
python3 single_stock_analyzer.py RELIANCE
# Without arguments, shows usage
python3 single_stock_analyzer.py
# Output: Usage: python3 analyze_stock.py <SYMBOL>
# Example: python3 analyze_stock.py RELIANCE
Programmatic Usage
from single_stock_analyzer import analyze_stock
# Analyze a stock programmatically
analyze_stock( "TCS" )
analyze_stock( "INFY" )
Source Code
import json
import sys
def get_float ( value_str ):
try :
return float (value_str)
except ( ValueError , TypeError ):
return 0.0
def calculate_change ( current , previous ):
if previous == 0 :
return 0.0
return ((current - previous) / abs (previous)) * 100
def get_value_from_pipe_string ( pipe_string , index ):
if not pipe_string:
return 0.0
parts = pipe_string.split( '|' )
if index < len (parts):
return get_float(parts[index])
return 0.0
def analyze_stock ( symbol_to_find ):
input_file = "fundamental_data.json"
try :
with open (input_file, "r" ) as f:
data = json.load(f)
except FileNotFoundError :
print ( f "Error: { input_file } not found." )
return
stock_data = None
for item in data:
if item.get( "Symbol" ) == symbol_to_find:
stock_data = item
break
if not stock_data:
print ( f "Stock ' { symbol_to_find } ' not found in database." )
return
# --- Extract Data Sections ---
cq = stock_data.get( "incomeStat_cq" , {})
cy = stock_data.get( "incomeStat_cy" , {})
ttm_cy = stock_data.get( "TTM_cy" , {})
cv = stock_data.get( "CV" , {})
roce_roe = stock_data.get( "roce_roe" , {})
shp = stock_data.get( "sHp" , {})
bs_c = stock_data.get( "bs_c" , {}) # Balance Sheet Consolidated
# Calculate all metrics (Net Profit, EPS, Sales, OPM, Ratios, etc.)
# ... [Full calculation logic from source code] ...
# Print comprehensive analysis
print ( f "--- Analysis for { symbol_to_find } ---" )
# ... [Full output format] ...
if __name__ == "__main__" :
if len (sys.argv) > 1 :
analyze_stock(sys.argv[ 1 ])
else :
print ( "Usage: python3 analyze_stock.py <SYMBOL>" )
print ( "Example: python3 analyze_stock.py RELIANCE" )
The full source code is 202 lines. See the complete implementation in /workspace/source/DO NOT DELETE EDL PIPELINE/single_stock_analyzer.py
Key Calculations
5-Year Sales CAGR
if sales_5_years_ago > 0 :
sales_growth_5y = ((sales_current_annual / sales_5_years_ago) ** ( 1 / 5 ) - 1 ) * 100
CAGR Formula: ((End Value / Start Value)^(1/n) - 1) * 100
Debt to Equity Ratio
non_current_liab = get_value_from_pipe_string(bs_c.get( "NON_CURRENT_LIABILITIES" ), 0 )
total_equity = get_value_from_pipe_string(bs_c.get( "TOTAL_EQUITY" ), 0 )
de_ratio = non_current_liab / total_equity if total_equity != 0 else 0.0
PEG Ratio
peg = 0.0
if yoy_eps > 0 :
peg = pe / yoy_eps
PEG = P/E Ratio / EPS Growth Rate
Forward P/E
if eps_latest > 0 :
annualized_eps = eps_latest * 4
ttm_eps = get_float(ttm_cy.get( "EPS" ))
if annualized_eps > 0 :
forward_pe = pe * (ttm_eps / annualized_eps)
Dependencies
json: Read fundamental data file
sys: Command-line argument handling
This utility has no external dependencies beyond Python standard library.
Error Handling
If fundamental_data.json doesn’t exist: Error: fundamental_data.json not found.
Solution: Run fetch_fundamental_data.py first to generate the data file.
If the symbol doesn’t exist in the database: Stock 'INVALID' not found in database.
Solution: Check the symbol spelling or verify it exists in fundamental_data.json.
If a stock has incomplete data, the analyzer returns 0.0 or “N/A” for missing fields rather than crashing.
Use Cases
Quick Screening Quickly check fundamentals before making investment decisions.
Quarterly Tracking Monitor quarter-over-quarter performance for portfolio stocks.
Comparative Analysis Analyze multiple stocks in the same sector by running the script repeatedly.
Automated Alerts Integrate into scripts to alert when specific metrics cross thresholds.
Integration with Pipeline
While this is a utility script, it integrates seamlessly with the main pipeline:
# Run the pipeline
python3 fetch_fundamental_data.py
# Immediately analyze any stock
python3 single_stock_analyzer.py RELIANCE
You can also create wrapper scripts for batch analysis:
# analyze_watchlist.py
from single_stock_analyzer import analyze_stock
watchlist = [ "RELIANCE" , "TCS" , "INFY" , "HDFCBANK" , "ICICIBANK" ]
for symbol in watchlist:
analyze_stock(symbol)
print ( " \n " + "=" * 50 + " \n " )